<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />
  
  <title>微信小程序结合ThinkPHP5实战项目（一）-- 数据库访问与ORM | 程序小工  | Just do it!</title>
  <meta name="description" content="遇见更好的自己~" />
  <meta name="keywords" content="" />
  <meta name="HandheldFriendly" content="True" />
  <meta name="apple-mobile-web-app-capable" content="yes">
  <link rel="shortcut icon" href="/">
  <link rel="alternate" href="/atom.xml" title="程序小工  | Just do it!">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="ThinkPHP5 从入门到深入学习，结合实战项目深入理解 ThinkPHP5 的特性和使用方法，了解 ThinkPHP5 的数据库访问和 ORM 思想，学习使用查询构造器、日志以及初步了解异常处理机制。">
<meta name="keywords" content="thinkphp5,微信小程序">
<meta property="og:type" content="article">
<meta property="og:title" content="微信小程序结合ThinkPHP5实战项目（一）-- 数据库访问与ORM">
<meta property="og:url" content="http://blog.i2arch.tech/2018/07/01/php-practice-wx-tp5-1/index.html">
<meta property="og:site_name" content="程序小工  | Just do it!">
<meta property="og:description" content="ThinkPHP5 从入门到深入学习，结合实战项目深入理解 ThinkPHP5 的特性和使用方法，了解 ThinkPHP5 的数据库访问和 ORM 思想，学习使用查询构造器、日志以及初步了解异常处理机制。">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://raw.githubusercontent.com/zqunor/MarkdownPic/master/thinkphp5+%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%95%86%E5%9F%8E/7-3tp5%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9E%B6%E6%9E%84.png">
<meta property="og:updated_time" content="2018-08-14T07:59:24.559Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="微信小程序结合ThinkPHP5实战项目（一）-- 数据库访问与ORM">
<meta name="twitter:description" content="ThinkPHP5 从入门到深入学习，结合实战项目深入理解 ThinkPHP5 的特性和使用方法，了解 ThinkPHP5 的数据库访问和 ORM 思想，学习使用查询构造器、日志以及初步了解异常处理机制。">
<meta name="twitter:image" content="https://raw.githubusercontent.com/zqunor/MarkdownPic/master/thinkphp5+%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%95%86%E5%9F%8E/7-3tp5%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9E%B6%E6%9E%84.png">
    
  <link href="https://fonts.googleapis.com/css?family=Inconsolata|Titillium+Web" rel="stylesheet">
  <link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
  <link href='//cdn.bootcss.com/node-waves/0.7.5/waves.min.css' rel='stylesheet'>
  <link rel="stylesheet" href="/style.css">
  <script>
    function setLoadingBarProgress(num) {
      document.getElementById('loading-bar').style.width=num+"%";
    }
  </script>
</head>

<body>
  <div id="loading-bar-wrapper">
  <div id="loading-bar"></div>
</div>


  <script>setLoadingBarProgress(20)</script>
  <header class="l_header">
	<div class='wrapper'>
		<div class="nav-main container container--flex">
			<a class="logo flat-box" href='/' >
				程序小工  | Just do it!
			</a>
			<div class='menu'>
				<ul class='h-list'>
					
						<li>
							<a class='flat-box nav-home' href='/'>
								<i class='icon icon-list2'></i>
								首页
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-archives' href='/archives'>
								<i class='icon icon-bookmark'></i>
								归档
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-about' href='/about'>
								<i class='icon icon-user'></i>
								关于
							</a>
						</li>
					
				</ul>
				<div class='underline'></div>
			</div>
			
				<div class="m_search">
					<form name="searchform" class="form u-search-form">
						<input type="text" class="input u-search-input" placeholder="Search" />
						<span class="icon icon-search"></span>
					</form>
				</div>
			
			<ul class='switcher h-list'>
				
					<li class='s-search'><a href='javascript:void(0)'><span class="icon icon-search flat-box"></span></a></li>
				
				<li class='s-menu'><a href='javascript:void(0)'><span class="icon icon-menu flat-box"></span></a></li>
			</ul>
		</div>

		<div class='nav-sub container container--flex'>
			<a class="logo" class="flat-box" href='javascript:void(0)'>
				Word of Forks
			</a>

			<ul class='switcher h-list'>
				<li class='s-comment'><a href='javascript:void(0)'><span class="icon icon-chat_bubble_outline flat-box"></span></a></li>
				<li class='s-top'><a href='javascript:void(0)'><span class="icon icon-arrow_upward flat-box"></span></a></li>
				<li class='s-toc'><a href='javascript:void(0)'><span class="icon icon-format_list_numbered flat-box"></span></a></li>
			</ul>
		</div>
	</div>
</header>
<aside class="menu-phone">
	<nav>
		
			<a href="/" class="nav-home nav">
				首页
			</a>
		
			<a href="/archives" class="nav-archives nav">
				归档
			</a>
		
			<a href="/about" class="nav-about nav">
				关于
			</a>
		
	</nav>
</aside>

    <script>setLoadingBarProgress(40);</script>
  <div class="l_body">
    <div class='container clearfix'>
      <!-- 左侧内容 -->
      <div class='l_main'>
        <article id="post-php-practice-wx-tp5-1"
  class="post white-box article-type-post"
  itemscope itemprop="blogPost">
	<section class='meta'>

	<h2 class="title">
  	<a href="/2018/07/01/php-practice-wx-tp5-1/">
    	微信小程序结合ThinkPHP5实战项目（一）-- 数据库访问与ORM
    </a>
	</h2>

	<div class="pagenav">
		<time>
			2018-07-01
		</time>

		
    
    <div class='cats'>
        <i class="icon icon-bookmark"></i>
        <a href="/categories/PHP/">PHP</a>
    </div>


		
			<div class="pagetags">
				<i class="icon icon-price-tag" style="margin-right: 2px;"></i>
				
					<a href="/tags/thinkphp5/" style="margin-left: 3px;">
						thinkphp5
					</a>
				
					<a href="/tags/微信小程序/" style="margin-left: 3px;">
						微信小程序
					</a>
				
			</div>
			
	</div>
	</section>

	
	<section class="toc-wrapper"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#72-从一个错误了解-exception-的继承关系"><span class="toc-text"> 7.2 从一个错误了解 Exception 的继承关系</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#73-tp5-数据库中间层架构解析"><span class="toc-text"> 7.3 TP5 数据库中间层架构解析</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#74-查询构造器一"><span class="toc-text"> 7.4 查询构造器一</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#75-查询构造器二"><span class="toc-text"> 7.5 查询构造器二</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#76-查询构造器三"><span class="toc-text"> 7.6 查询构造器三</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#77-开启-sql-日志记录"><span class="toc-text"> 7.7 开启 SQL 日志记录</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-8-orm-与模型"><span class="toc-text"> 7-8 ORM 与模型</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#7-9-初识模型"><span class="toc-text"> 7-9 初识模型</span></a></li></ol></section>
	

	<section class="article typo">
		<div class="article-entry" itemprop="articleBody">
				<span class="zhaiyao">[摘要]</span>
			<p>ThinkPHP5 从入门到深入学习，结合实战项目深入理解 ThinkPHP5 的特性和使用方法，了解 ThinkPHP5 的数据库访问和 ORM 思想，学习使用查询构造器、日志以及初步了解异常处理机制。</p>
<a id="more"></a>
<h2 id="72-从一个错误了解-exception-的继承关系"><a class="markdownIt-Anchor" href="#72-从一个错误了解-exception-的继承关系"></a> 7.2 从一个错误了解 Exception 的继承关系</h2>
<p>1.将<code>Exception</code>修改为全局<code>Exception</code>基类，而不是<code>think\Exception</code></p>
<pre><code>`think\Exception =&gt; \Exception =&gt;  Throwable`
`HttpException =&gt; \RuntimeException =&gt;  \Exception =&gt;  Throwable`
</code></pre>
<p><strong>当访问的控制器不存在、url 错误时，属于 HttpException 异常。</strong> 而原先定义的<code>render()</code>和<code>recordErrorLog()</code>方法要求接收的参数类型是<code>think\Exception</code>，由于<code>HttpException</code>不是继承于<code>think\Exception</code>，不能转化为<code>think\Exception</code>，所以会报错。</p>
<blockquote>
<p>解决：使用全局 Exception 基类后，既支持 HttpException，又支持 think\Exception。子类可以自动被转化为父类的类型。<br>
Exception 基类是所有异常类的基类。</p>
</blockquote>
<p>2.<strong>补充</strong>：PHPStrom 快捷键：</p>
<ul>
<li>ctrl+alt+O =&gt; 快速删除没有 use 的类</li>
</ul>
<h2 id="73-tp5-数据库中间层架构解析"><a class="markdownIt-Anchor" href="#73-tp5-数据库中间层架构解析"></a> 7.3 TP5 数据库中间层架构解析</h2>
<p><img src="https:raw.githubusercontent.com/zqunor/MarkdownPic/master/thinkphp5+%E5%B0%8F%E7%A8%8B%E5%BA%8F%E5%95%86%E5%9F%8E/7-3tp5%E6%95%B0%E6%8D%AE%E5%BA%93%E6%9E%B6%E6%9E%84.png" alt="tp5数据库架构"></p>
<h2 id="74-查询构造器一"><a class="markdownIt-Anchor" href="#74-查询构造器一"></a> 7.4 查询构造器一</h2>
<p>1、为什么不使用原生的查询语句而使用查询构造器？</p>
<ul>
<li>简洁方便</li>
<li>对不同数据库的操作进行了封装，使用统一的数据库操作标准</li>
</ul>
<p>2、对查询构造器的理解</p>
<ul>
<li>查询构造器不仅仅是对数据库进行读操作，还包括数据库的写操作</li>
<li>查询构造器仅仅是语法，最终都是通过 Builder 翻译成 SQL 语句来执行</li>
</ul>
<h2 id="75-查询构造器二"><a class="markdownIt-Anchor" href="#75-查询构造器二"></a> 7.5 查询构造器二</h2>
<p>1.查询语句 = 链式方法 + 执行方法</p>
<p>2.链式方法：</p>
<ul>
<li>where</li>
<li>whereOr</li>
<li>field</li>
<li>…</li>
</ul>
<p>只会返回 Query 对象，不是查询结果</p>
<p>3.执行方法：</p>
<ul>
<li>
<p>find</p>
</li>
<li>
<p>select</p>
</li>
<li>
<p>update</p>
</li>
<li>
<p>delete</p>
</li>
<li>
<p>insert</p>
<p>4.<strong>在执行方法调用前，查询状态是保留的，直到调用执行方法后，状态才会被清除</strong></p>
</li>
</ul>
<h2 id="76-查询构造器三"><a class="markdownIt-Anchor" href="#76-查询构造器三"></a> 7.6 查询构造器三</h2>
<p>1.链式方法说明（where）：</p>
<blockquote>
<p>where(‘字段名’,‘表达式’,‘查询条件’)</p>
</blockquote>
<p>2.三种实现方式：</p>
<ul>
<li>
<p>表达式</p>
</li>
<li>
<p>数组法（不够灵活，且存在一定的安全问题）</p>
</li>
<li>
<p>闭包（最灵活）</p>
</li>
</ul>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 通过use来使用外部的数据</span></span><br><span class="line">where(<span class="function"><span class="keyword">function</span> <span class="params">($query)</span> <span class="title">use</span> <span class="params">($id)</span></span>&#123;</span><br><span class="line">    $query-&gt;where(<span class="string">'banner_id'</span>, <span class="string">'='</span>, $id)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
<h2 id="77-开启-sql-日志记录"><a class="markdownIt-Anchor" href="#77-开启-sql-日志记录"></a> 7.7 开启 SQL 日志记录</h2>
<p>1.database.php =》 debug=true</p>
<p>2.config.php =》 app_debug=true</p>
<p>3.config.php =》 log =》 level =》sql</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">'log'</span>                    =&gt; [</span><br><span class="line">     日志记录方式，内置 file socket 支持扩展</span><br><span class="line">    <span class="string">'type'</span>  =&gt; <span class="string">'File'</span>,</span><br><span class="line">     日志保存目录</span><br><span class="line">    <span class="string">'path'</span>  =&gt; LOG_PATH,</span><br><span class="line">     日志记录级别</span><br><span class="line">    <span class="string">'level'</span> =&gt; [<span class="string">'error'</span>, <span class="string">'sql'</span>],</span><br><span class="line">],</span><br></pre></td></tr></table></figure>
<p>不在配置文件中开启日志</p>
<p><code>ExceptionHandler</code>=&gt;<code>recordErrorLog</code> 方法中开启日志仅仅在发生异常时写入。</p>
<p>所以对于全局的情况，将日志手动添加到入口文件中，对所有调用都开启 sql 日志</p>
<p>？？这样和在配置文件中开启日志有什么区别？</p>
<h2 id="7-8-orm-与模型"><a class="markdownIt-Anchor" href="#7-8-orm-与模型"></a> 7-8 ORM 与模型</h2>
<p>1.ORM 理解：</p>
<p>ORM = <code>Object Relationship Map</code></p>
<p>对象关系映射:将每张数据表看作是一个对象</p>
<p>2.模型（TP5 模型）–ORM 实现的具体机制<br>
=&gt; <code>业务的集合= 数据库查询+业务逻辑+...</code></p>
<p>【注】模型与数据表不是一一对应的关系，简单的业务逻辑看上去是一张表对应一个模型，但复杂的业务逻辑（需要分层）可能是横跨多个表。</p>
<p>模型不仅仅只是 model 这一层，复杂的业务还可以继续划分，tp5 中有 <code>model</code>(数据层，细)，<code>service</code>(服务层，粗)，<code>logic</code>(逻辑层)</p>
<h2 id="7-9-初识模型"><a class="markdownIt-Anchor" href="#7-9-初识模型"></a> 7-9 初识模型</h2>
<p>1.<code>model/Banner.php</code> 继承 Model 类之后，就成为了模型，就可以使用模型类已经封装好的方法(<code>get</code>)，而不用自定义方法(<code>getBannerById</code>)。</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$banner = BannerModel::getBannerById($id);</span><br><span class="line"> <span class="comment">// =&gt; 返回数组</span></span><br><span class="line"> <span class="comment">//等价于</span></span><br><span class="line">$banner = BannerModel::get($id);</span><br><span class="line"><span class="comment">// =&gt; 返回对象，便于处理查询结果</span></span><br></pre></td></tr></table></figure>
<p>2.tp5 自动将对象序列化，序列化的格式根据配置文件中的配置项<code>default_return_type</code>转化为相应的格式。</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// config.php</span></span><br><span class="line"><span class="string">'default_return_type'</span> =&gt; <span class="string">'html'</span></span><br></pre></td></tr></table></figure>
<p>3.自定义模型方法(<code>getBannerById</code>)调用的是指定的数据表，而模型类自动的方法(<code>get</code>)调用的是模型类名对应的数据表。</p>

		</div>

		
			<div class="art-item-footer">
					
						<span class="art-item-left"><i class="icon icon-chevron-thin-left"></i> <a href="/2018/07/05/http-ouath/" rel="prev" title="【PHP】第三方登录OAuth2.0">
							【PHP】第三方登录OAuth2.0
						</a>上一篇文章</span>
					
					
						<span class="art-item-right">下一篇文章：<a href="/2018/06/29/windows-tool/" rel="next"  title="【转】windows系统下的高效工具">
							【转】windows系统下的高效工具
						</a><i class="icon icon-chevron-thin-right"></i></span>
					
			</div>
		

		
			

    <div class="recommended_posts">
        <h3>推荐文章</h3>
        <ul>
            
                <li><a href="http://blog.i2arch.tech/2018/07/05/php-practice-wx-tp5-2/">微信小程序结合ThinkPHP5实战项目（二）-- 接口编写</a></li>
            
                <li><a href="http://blog.i2arch.tech/2018/07/05/http-ouath/">【PHP】第三方登录OAuth2.0</a></li>
            
                <li><a href="http://blog.i2arch.tech/2018/06/29/windows-tool/">【转】windows系统下的高效工具</a></li>
            
                <li><a href="http://blog.i2arch.tech/2018/06/22/vscode-background/">【VSCode插件】background添加编辑器背景</a></li>
            
        </ul>
    </div>


		
	</section>

	

</article>
<script>
	window.subData = {
		title: '微信小程序结合ThinkPHP5实战项目（一）-- 数据库访问与ORM',
		tools: true
	}
</script>

      </div>

      <!-- 右侧边栏组件 -->
      <aside class='l_side'>
        
      </aside>

      <div class="gotop">
          
    <a href='javascript:void(0)'>
        <i class="icon icon-arrow_upward flat-box">
        </i>
    </a>

      </div>
      <script>setLoadingBarProgress(60);</script>
    </div>
  </div>
  <footer id="footer" class="clearfix">

	<div class="social-wrapper">
  	
      
        <a href="https://github.com/zqunor" class="social github"
          target="_blank" rel="external">
          <span class="icon icon-github"></span>
        </a>
      
        <a href="https://www.cnblogs.com/zqunor" class="social zhihu"
          target="_blank" rel="external">
          <span class="icon icon-zhihu"></span>
        </a>
      
        <a href="/atom.xml" class="social rss"
          target="_blank" rel="external">
          <span class="icon icon-rss"></span>
        </a>
      
    
  </div>
  <div>Theme <a href='https://github.com/stkevintan/hexo-theme-material-flow' class="codename">MaterialFlow</a>  Powered by<a href="https://blog.i2arch.tech/" target="_blank">程序小工</a>.</div>

</footer>

  <script>setLoadingBarProgress(80);</script>
  

    <script src="//apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
    <script src='//cdn.bootcss.com/node-waves/0.7.5/waves.min.js'></script>
    <script src="//cdn.bootcss.com/scrollReveal.js/3.3.2/scrollreveal.min.js"></script>
    <script src="/js/jquery.fitvids.js"></script>
      <script>
        var GOOGLE_CUSTOM_SEARCH_API_KEY = "";
        var GOOGLE_CUSTOM_SEARCH_ENGINE_ID = "";
        var ALGOLIA_API_KEY = "";
        var ALGOLIA_APP_ID = "";
        var ALGOLIA_INDEX_NAME = "";
        var AZURE_SERVICE_NAME = "";
        var AZURE_INDEX_NAME = "";
        var AZURE_QUERY_KEY = "";
        var BAIDU_API_ID = "fca5b83cf69f752ddc96a61ef64a3659";
        var SEARCH_SERVICE = "hexo";
        var ROOT = "/" || "/";
        if (!ROOT.endsWith('/')) ROOT += '/';
      </script>
      <script src="/js/search.js"></script>
        <script src="/js/app.js"></script>
  <script>setLoadingBarProgress(100);</script>
</body>
</html>
